package model.dao;

import javax.persistence.EntityManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import model.util.EntityManagerUtil;
import model.domain.Task;
import java.util.List;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import model.domain.Product;
import model.domain.Sprint;
import model.domain.Status;


@Repository
@Transactional
public class TaskDao {
	private static final Log log = LogFactory.getLog(TaskDao.class);

	@PersistenceContext
	private EntityManager entityManager;

	public void insert(Task transientInstance) {
		log.debug("inserting SprintBacklog instance");
		try {
			entityManager = EntityManagerUtil.getEntityManager();
			entityManager.getTransaction().begin();
			entityManager.persist(transientInstance);
			entityManager.getTransaction().commit();
			log.debug("insert successful");
		} catch (RuntimeException re) {
			log.error("insert failed", re);
			throw re;
		}
	}

	public void delete(Task persistentInstance) {
		log.debug("deleting SprintBacklog instance");
		try {
			entityManager = EntityManagerUtil.getEntityManager();
			entityManager.getTransaction().begin();
			persistentInstance = entityManager.merge(persistentInstance);
			entityManager.remove(persistentInstance);
                        entityManager.getTransaction().commit();
			log.debug("delete successful");
		} catch (RuntimeException re) {
			log.error("delete failed", re);
			throw re;
		}
	}

	public void insertOrUpdate(Task detachedInstance) {
		log.debug("inserting or updating SprintBacklog instance");
		try {
			entityManager = EntityManagerUtil.getEntityManager();
			entityManager.getTransaction().begin();
			detachedInstance = entityManager.merge(detachedInstance);
			entityManager.persist(detachedInstance);
                        entityManager.getTransaction().commit();
			log.debug("insert or update successful");
		} catch (RuntimeException re) {
			log.error("insert or update failed", re);
			throw re;
		}
	}

	public Task findById(Integer id) {
		log.debug("getting SprintBacklog instance with id: " + id);
		try {
			entityManager = EntityManagerUtil.getEntityManager();
			Task instance = entityManager.find(Task.class, id);
			log.debug("get successful");
			return instance;
		} catch (RuntimeException re) {
			log.error("get failed", re);
			throw re;
		}
	}

	public List<Task> getAll() {
		log.debug("getting all SprintBacklog instances");
		try {
			entityManager = EntityManagerUtil.getEntityManager();
			@SuppressWarnings("unchecked")
			Query query = entityManager.createQuery("from Task");
			log.debug("get successful");
			return query.getResultList();
		} catch (RuntimeException re) {
			log.error("get failed", re);
			throw re;
		}
	}

        public List<Task> findByProduct(Product product) {
		log.debug("getting all ProductBacklog instances");
		try {
			entityManager = EntityManagerUtil.getEntityManager();
			@SuppressWarnings("unchecked")
			Query query = entityManager.createQuery("SELECT t FROM Task t WHERE t.productbacklog = :product");
                        query.setParameter("product", product);
			log.debug("get successful");
			return query.getResultList();
		} catch (RuntimeException re) {
			log.error("get failed", re);
			throw re;
		}
	}

        public List<Task> findBySprint(Sprint sprint) {
		log.debug("getting all ProductBacklog instances");
		try {
			entityManager = EntityManagerUtil.getEntityManager();
			@SuppressWarnings("unchecked")
			Query query = entityManager.createQuery("SELECT t FROM Task t"
                                + " WHERE t.productbacklog.sprint = :sprint order by t.end");
                        query.setParameter("sprint", sprint);
			log.debug("get successful");
			return query.getResultList();
		} catch (RuntimeException re) {
			log.error("get failed", re);
			throw re;
		}
	}

        public Long sumEstimatedEffortBySprint(Sprint sprint) {
		log.debug("getting all ProductBacklog instances");
		try {
			entityManager = EntityManagerUtil.getEntityManager();
			@SuppressWarnings("unchecked")
			Query query = entityManager.createQuery("SELECT sum(t.estimatedEffort) FROM Task t"
                                + " WHERE t.productbacklog.sprint = :sprint)");
                        query.setParameter("sprint", sprint);
			log.debug("get successful");
			Long sum = (Long) query.getResultList().iterator().next();
                        if(sum == null)
                            sum = Long.valueOf(0);
                        return sum;
		} catch (RuntimeException re) {
			log.error("get failed", re);
			throw re;
		}
	}

        public List<Task> findBySprintAndStatus(Sprint sprint, Status status) {
		log.debug("getting all ProductBacklog instances");
		try {
			entityManager = EntityManagerUtil.getEntityManager();
			@SuppressWarnings("unchecked")
			Query query = entityManager.createQuery("SELECT t FROM Task t"
                                + " WHERE t.productbacklog.sprint = :sprint and t.status = :status order by t.end");
                        query.setParameter("sprint", sprint);
                        query.setParameter("status", status);
			log.debug("get successful");
			return query.getResultList();
		} catch (RuntimeException re) {
			log.error("get failed", re);
			throw re;
		}
	}
}
